package com.suzhe.ymall.product.service.impl;

import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.suzhe.ymall.common.enums.MessageStatusEnum;
import com.suzhe.ymall.common.exception.YMallException;
import com.suzhe.ymall.common.pojo.ApiResEntity;
import com.suzhe.ymall.common.utils.YMJsonUtils;
import com.suzhe.ymall.product.mapper.SkuMapper;
import com.suzhe.ymall.product.param.LockStockParam;
import com.suzhe.ymall.product.param.OrderSkuParam;
import com.suzhe.ymall.product.pojo.Sku;
import com.suzhe.ymall.product.pojo.Stock;
import com.suzhe.ymall.product.pojo.StockLockDetail;
import com.suzhe.ymall.product.service.IMessageLogService;
import com.suzhe.ymall.product.service.ISkuService;
import com.suzhe.ymall.product.service.IStockLockDetailService;
import com.suzhe.ymall.product.service.IStockService;
import lombok.extern.slf4j.Slf4j;
import org.apache.curator.framework.recipes.locks.InterProcessMutex;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.scheduling.annotation.Async;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.Date;
import java.util.List;
import java.util.Map;
import java.util.concurrent.TimeUnit;
import java.util.stream.Collectors;

/**
 * <p>
 * sku表 服务实现类
 * </p>
 *
 * @author suzhe
 * @since 2019-07-24
 */
@Service
@Slf4j
public class SkuServiceImpl extends ServiceImpl<SkuMapper, Sku> implements ISkuService {


    @Autowired
    IStockService iStockService;

    @Autowired
    InterProcessMutex stockLock;

    @Autowired
    IStockLockDetailService iStockLockDetailService;

    @Autowired
    IMessageLogService iMessageLogService;

    @Transactional
    @Override
    public ApiResEntity lockStock(LockStockParam lockStockParam) {
        boolean lock = false;
        try {
            //分布式锁
            lock = stockLock.acquire(5, TimeUnit.SECONDS);
            if (lock) {
                //生成锁定明细
                StockLockDetail stockLockDetail = new StockLockDetail();
                stockLockDetail.setOrderNo(lockStockParam.getOrderNo());
                stockLockDetail.setLockTime(new Date());
                stockLockDetail.setDetail(YMJsonUtils.toJson(lockStockParam.getOrderSkuParams()));
                iStockLockDetailService.save(stockLockDetail);
                //扣减sku的库存数量
                Map<Integer, Integer> skuNumMap = lockStockParam.getOrderSkuParams().stream().collect(Collectors.toMap(c -> c.getSkuId(), c -> c.getNum()));
                List<Stock> stocks = (List) iStockService.listByIds(skuNumMap.keySet());
                for (Stock stock : stocks) {
                    Integer num = stock.getStock() - skuNumMap.get(stock.getSkuId());
                    if (num < 0) {
                        Sku sku = getById(stock.getSkuId());
                        return ApiResEntity.error(sku.getTitle() + "已售完");
                    }
                    stock.setStock(num);
                }
                iStockService.updateBatchById(stocks);
                return ApiResEntity.ok();
            }
        } catch (Exception e) {
            log.error("decreaseStock error", e);
        } finally {
            if (lock) {
                try {
                    stockLock.release();
                } catch (Exception e) {
                    log.error("decreaseStock release", e);
                }
            }
        }
        log.error("lockStock fail:{}", lockStockParam);
        return ApiResEntity.error("库存更新失败");

    }

    @Async("asyncServiceExecutor") //此处方法实现被加入到线程池中执行。当前的方法立刻返回，上级调用即可结束
    @Transactional
    @Override
    public void rollbackOrder(String messageId,String orderNo){
        StockLockDetail stockLockDetail = iStockLockDetailService.getById(orderNo);
        if (stockLockDetail != null){
            boolean lock = false;
            try {
                lock = stockLock.acquire(5, TimeUnit.SECONDS);
                if (lock) {
                    List<OrderSkuParam> orderSkuParams = YMJsonUtils.toList(stockLockDetail.getDetail(), OrderSkuParam.class);
                    //扣减sku的库存数量
                    Map<Integer, Integer> skuNumMap = orderSkuParams.stream().collect(Collectors.toMap(c -> c.getSkuId(), c -> c.getNum()));
                    List<Stock> stocks = (List) iStockService.listByIds(skuNumMap.keySet());
                    for (Stock stock : stocks) {
                        Integer num = stock.getStock() + skuNumMap.get(stock.getSkuId());
                        stock.setStock(num);
                    }
                    iStockService.updateBatchById(stocks);
                    iStockLockDetailService.removeById(orderNo);
                }else{
                    //发送报警消息
                    throw new YMallException(orderNo + "回滚，获取库存锁失败");
                }
            }catch (Exception e){
                log.error("库存回滚失败",e);
                //发送报警消息
                throw new YMallException(orderNo + "库存回滚失败");
            } finally {
                if (lock) {
                    try {
                        stockLock.release();
                    } catch (Exception e) {
                        log.error("decreaseStock release", e);
                        //发送报警消息
                    }
                }
            }
        }

    }

    @Async("asyncServiceExecutor") //此处方法实现被加入到线程池中执行。当前的方法立刻返回，上级调用即可结束
    @Override
    public void orderSuccess(String messageId,String orderNo) {
        StockLockDetail stockLockDetail = iStockLockDetailService.getById(orderNo);
        if (stockLockDetail != null){
            iStockLockDetailService.removeById(stockLockDetail.getOrderNo());
        }

        iMessageLogService.updateMeesageStatus(messageId, MessageStatusEnum.DONE);
    }
}
